#include"common_headers.h"

int naryRoot(struct FileDescriptor *fd_Desc1)
{

    nroot=(struct narytree *)malloc(sizeof(struct narytree));
    nroot->mydes=fd_Desc1;
    nroot->leftsibling=NULL;
    nroot->child=NULL;
    nroot->rightsibling=NULL;
    nroot->parent=NULL;
    return 1;
}

struct narytree * allocNode()
{
	struct narytree *tmp;
	tmp=(struct narytree *)malloc(sizeof(struct narytree));
	tmp->mydes=NULL;
     tmp->child=NULL;
     tmp->rightsibling=NULL;
     tmp->leftsibling=NULL;
	tmp->parent=NULL;
	return (tmp);
}


int checkPath(struct narytree *n1,struct narytree *tmp)
{
	int flag;
	if(strncmp(n1->mydes->locationpath,tmp->mydes->locationpath,strlen(tmp->mydes->locationpath))==0 && (tmp==nroot || n1->mydes->locationpath[strlen(tmp->mydes->locationpath)]=='/'))
		flag= 1;

	else
	{
		flag= 0;
	}
return flag;
}


int isValid(char pathname[300],struct narytree *tmp)
{
	int flag;
	if(strncmp(pathname,tmp->mydes->locationpath,strlen(tmp->mydes->locationpath))==0 && (tmp==nroot || pathname[strlen(tmp->mydes->locationpath)]=='/'))
		flag= 1;
	else
		flag= 0;

return flag;
}

int parsePath(struct FileDescriptor *fd_Desc1,struct narytree *tmp)
{
	int flag;
	if(strncmp(fd_Desc1->locationpath,tmp->mydes->locationpath,strlen(tmp->mydes->locationpath))==0 && (tmp==nroot || fd_Desc1->locationpath[strlen(tmp->mydes->locationpath)]=='/'))
		flag= 1;
	else
		flag= 0;

return flag;
}


int rightSiblingCheck(struct narytree *tmp)
{
	int flag;

	if(tmp->rightsibling==NULL)
	{
		flag=1;
	}	
	else if(tmp->rightsibling!=NULL)
	{
		flag=2;
	}

return flag;

}

int leftSiblingCheck(struct narytree *tmp)
{
	int flag;

	if(tmp->leftsibling==NULL)
	{
		flag=1;
	}	
	else if(tmp->leftsibling!=NULL)
	{
		flag=2;
	}

return flag;
}


int insert_nary(struct FileDescriptor *fd_Desc1)
{
    struct narytree *tmp,*newadd;
    int rightvalid,collect=0;
    tmp=nroot;

    while(1)
    {

	rightvalid=rightSiblingCheck(tmp);

        if(parsePath(fd_Desc1,tmp))
        {
            if(tmp->child==NULL)
            {
                newadd=allocNode();
                tmp->child=newadd;
                newadd->mydes=fd_Desc1;
                newadd->parent=tmp;
                collect=1;
			return collect;
            }
            else
            {
                tmp=tmp->child;
            }
        }
        else if((rightvalid==1) && tmp!=nroot)
        {
            newadd=allocNode();
            tmp->rightsibling=newadd;
            newadd->mydes=fd_Desc1;
            newadd->leftsibling=tmp;

            if(tmp->parent!=NULL)
	    {		
	    	newadd->parent=tmp->parent;
	    }
            else 
	    {
		newadd->parent=NULL;
	    }
            collect= 1;
		return collect;

        }
        else if(rightvalid==2)
        {
            tmp=tmp->rightsibling;
        }
        else if((rightvalid==1) && tmp==nroot)
        {
            collect= 0;
			return collect;
        }


    }


}

int comparePath(char pathname[300],struct narytree *tmp)
{
	int flag;

	if(strcmp(pathname,tmp->mydes->locationpath)<0)
	{
		flag=1;
	}
	if(strcmp(pathname,tmp->mydes->locationpath)==0)
	{
		flag=2;
	}
	if(strcmp(pathname,tmp->mydes->locationpath)>0)
	{
		flag=3;
	}
	
	return flag;
}

int search_nary(char pathname[300])
{
    struct narytree *tmp,*newadd;
    int collect=0;
    searched_Descriptor=NULL; //initialize the searched descriptors
    tmp=nroot;
    int valid,rightvalid,comparepath;
    if(tmp==NULL) 
    {
	return collect; 
   }
    else
    {


        while(1)
        {

	    valid=isValid(pathname,tmp);

	    rightvalid=rightSiblingCheck(tmp);

	    comparepath=comparePath(pathname,tmp);

            if(comparepath==2)
            {
                searched_Descriptor=tmp->mydes;
                collect=1;
			return collect;

            }
	    
            else if(valid)
            {
                if(tmp->child!=NULL)
                {
				tmp=tmp->child;                    
				
                }

                else
                {
                    collect=0;
				return collect;
                }
            }
            else if(rightvalid==1)
            {
                collect=0;
			return collect;
            }
            else if(rightvalid==2)
            {
                tmp=tmp->rightsibling;
            }



        }
    }
}

int updateCheck(struct FileDescriptor *fd_Desc1,struct narytree *tmp)
{
	int flag;
	if(strcmp(fd_Desc1->locationpath,tmp->mydes->locationpath)==0 && strcmp(tmp->mydes->filetype,"dummy")==0)
		flag= 1;
	else
		flag= 0;	

return flag;
}



int update_nary(struct FileDescriptor *fd_Desc1)
{
    struct narytree *tmp,*newadd;
    tmp=nroot;
    int valid,upvalid,rightvalid,collect=0;
    if(tmp==NULL) {
	collect=0;
		}
    
    else
    {


        while(1)
        {

	    upvalid=updateCheck(fd_Desc1,tmp);

	    valid=parsePath(fd_Desc1,tmp);
	
	    rightvalid=rightSiblingCheck(tmp);

            if(upvalid)
            {
                tmp->mydes=fd_Desc1;

                collect=1;
			return collect;
            }
	    

            else if(valid)
            {
	        upvalid=updateCheck(fd_Desc1,tmp);

                if(tmp->child==NULL)
                {
                    if(upvalid)
                    {
                        tmp->mydes=fd_Desc1;

                        collect=1;
					return collect;
                    }
                    else {
					collect=0;
					return collect;				
				}
                }
		
                else
                {
		    upvalid=updateCheck(fd_Desc1,tmp);

                    if(upvalid)
                    {
                        tmp->mydes=fd_Desc1;

                        collect=1;
					return collect;
                    }
                    else tmp=tmp->child;
                }
            }
	  
            else if(rightvalid==1)
            {
		upvalid=updateCheck(fd_Desc1,tmp);

                if(upvalid)
                {
                    tmp->mydes=fd_Desc1;

                    collect= 1;
				return collect;
                }
                else 
		{
		    return collect;
		}
            }
            else if(rightvalid==2)
            {
		upvalid=updateCheck(fd_Desc1,tmp);

                if(upvalid)
                {
                    tmp->mydes=fd_Desc1;

                    collect=1;
				return collect;
                }
                else 
		{
		    tmp=tmp->rightsibling;
		}
            }



        }
    }
}



int print_nary(struct narytree *tmp)
{
    int collect=0;
    if(tmp!=NULL)
    {
        print_nary(tmp->child);
        printf("\n");
        printf("%s",tmp->mydes->locationpath);
        print_nary(tmp->rightsibling);
        collect=1;
    }
    return collect;

}

int nonrecur_nary(struct narytree *tmp, FILE *fp)
{
    int collect=0;


    if(tmp!=NULL)
    {
        fprintf(fp,"%s\t",tmp->mydes->locationpath);

        nonrecur_nary(tmp->rightsibling,fp);
        collect=1;
    }

    return collect;

}
int recur_nary(struct narytree *tmp, FILE *fp)
{
    int collect=0;

    if(tmp!=NULL)
    {
        fprintf(fp,"%s",tmp->mydes->locationpath);
        if(tmp->rightsibling!=NULL) fprintf(fp,"\t");
        recur_nary(tmp->rightsibling,fp);
        if(tmp->child!=NULL) fprintf(fp,"\n");
        recur_nary(tmp->child,fp);
        collect=1;
    }


    return collect;

}

void freeDir(struct narytree *tmp,struct narytree *tempo)
{
	tempo=tmp;
	mainHeader.usedFileDescriptors--;
	freelist[tmp->mydes->locationblocknumber]=0;
	free_nary(tempo->child);			                        				                        		                        
}

int delete_nary(char pathname[300])// this delete directory is only for directories not for files
{

    struct narytree *tmp,*newadd;
    tmp=nroot;
    int valid;
    int rightvalid,leftvalid,comparepath;
    if(tmp==NULL) 
    {
	return 0;
    }
    else
    {
	comparepath=comparePath(pathname,tmp);

        if(comparepath==2)//should not delete root
        {
            return 0;
        }
        else
        {


            while(1)
            {
		comparepath=comparePath(pathname,tmp);

		valid=isValid(pathname,tmp);

                if(valid)
                {
                    if(tmp->child==NULL)
                    {

                        printf("\ndeletedir_FAILURE %s",ERR_VFS_DELETEDIR_01);
                            return 0;
                    }

                    else
                    {

                        tmp=tmp->child;
                    }
                }
                else if(strcmp(pathname,tmp->mydes->locationpath)!=0)
                {
			rightvalid=rightSiblingCheck(tmp);

			if(rightvalid==1)
			{
                     		printf("\ndeletedir_FAILURE %s",ERR_VFS_DELETEDIR_01);
                            	return 0;
                	}
                	else if(rightvalid==2)
                	{

                    		tmp=tmp->rightsibling;
                	}

		}

                if(comparepath==2)
                {


                    if(tmp->child!=NULL)
                    {
                         printf("\ndeletedir_FAILURE %s",ERR_VFS_DELETEDIR_02);
                            return 0;
                    }
                    
                    else if(tmp->parent!=NULL)
                    {
			rightvalid=rightSiblingCheck(tmp);

			if(rightvalid==2)
				{
					leftvalid=leftSiblingCheck(tmp);

					if(leftvalid==2)
					{

			                        struct narytree *tempo;
						freeDir(tmp,tempo);			                       
			                        tmp->leftsibling->rightsibling=tmp->rightsibling;
			                        tmp->rightsibling->leftsibling=tmp->leftsibling;
			                        if(tmp->child!=NULL)
			                        {
			                            tmp->child->parent=NULL;
			                        }
	
			                        free(tmp);
			                        return 1;
			               }

				       else if(leftvalid==1) 
                			{
                        			
						struct narytree *tempo;
			                        freeDir(tmp,tempo);
			                        tmp->rightsibling->leftsibling=NULL;
			                        tmp->parent->child=tmp->rightsibling;
			                        if(tmp->child!=NULL)
			                        {
			                            tmp->child->parent=NULL;
			                        }

			                        free(tmp);
			                        return 1;
			                 }
				}

                    	else if (rightvalid==1) 
			{
				leftvalid=leftSiblingCheck(tmp);

				if(leftvalid==1)
                   		 {
                       				struct narytree *tempo;
                        			freeDir(tmp,tempo);
                        		 	tmp->parent->child=NULL;
                        			if(tmp->child!=NULL)
                        			{
                            		             tmp->child->parent=NULL;
                        			}

                        			free(tmp);
                        			return 1;
                    		}

				else if(leftvalid==2)
				{

					struct narytree *tempo;
                        		freeDir(tmp,tempo);
                        		tmp->leftsibling->rightsibling=NULL;
                        		if(tmp->child!=NULL)
                        		{
                            			tmp->child->parent=NULL;
                        		}

                        		free(tmp);
                        		return 1;
                		}

			}
       		 }
    	}
      }
    }
  }
}
int free_nary(struct narytree *tmp)
{
    int x=0;

    //tmp=nroot;
    if(tmp!=NULL)
    {
        free_nary(tmp->child);
        //printf("%s\n",tmp->mydes->locationpath);
        mainHeader.usedFileDescriptors--;
        //printf("->%s",tmp->mydes->locationpath);
        freelist[tmp->mydes->locationblocknumber]=0;
        free_nary(tmp->rightsibling);
        x=1;
    }
    return x;

}


int move_nary(struct narytree *n1)//similar to insert
{

    struct narytree *tmp;

    int rightvalid;

    tmp=nroot;

    while(1)
    {
	rightvalid=rightSiblingCheck(tmp);
	
        if(checkPath(n1,tmp))
        {

            if(tmp->child==NULL)
            {
                tmp->child=n1;
                n1->parent=tmp;
                BSTInsert(n1->mydes);
                if(n1->child!=NULL) 
		{
			movepath_nary(n1->child);
		}
                return 1;

            }

            else
            {
                tmp=tmp->child;
            }
        }
        else if(rightvalid==1)
        {

		if(tmp!=nroot)
		{
            		
			tmp->rightsibling=n1;
            		n1->leftsibling=tmp;
            		if(tmp->parent!=NULL)
			{
				n1->parent=tmp->parent;
			}
            		else 
			{
				n1->parent=NULL;
			}
	                BSTInsert(n1->mydes);
            		if(n1->child!=NULL) 
			{
				movepath_nary(n1->child);
			}
            		return 1;

		}

		else if(tmp==nroot)
		{
			return 0;
		}

	}
        else if(rightvalid==2)
        {
            tmp=tmp->rightsibling;
        }
     
    }



}

int movepath_nary(struct narytree *root)
{
    int x=0;

    //tmp=nroot;
    if(root!=NULL)
    {
        delete_bstnode(bst_root,root->mydes->locationpath);
        strcpy(root->mydes->locationpath,root->parent->mydes->locationpath);
        strcat(root->mydes->locationpath,"/");
        strcat(root->mydes->locationpath,root->mydes->filename);
        BSTInsert(root->mydes);
        movepath_nary(root->child);
        movepath_nary(root->rightsibling);
        x=1;
    }
    return x;

}


int delete_file_from_nary(char pathname[300])// this delete directory is only for directories not for files
{
    struct narytree *tmp;
    tmp=nroot;
    int valid,rightvalid,leftvalid,comparepath;
    while(1)
    {
	valid=isValid(pathname,tmp);

	comparepath=comparePath(pathname,tmp);

        if(valid)
        {

            tmp=tmp->child;

        }

        else if(tmp->rightsibling!=NULL && strcmp(pathname,tmp->mydes->locationpath)!=0)
        {

            tmp=tmp->rightsibling;
        }

        if(comparepath==2)
        {
            if(tmp->parent!=NULL)
            {
			rightvalid=rightSiblingCheck(tmp);

			if(rightvalid==1)
			{
				leftvalid=leftSiblingCheck(tmp);

				if(leftvalid==2)
				{

			                tmp->leftsibling->rightsibling=NULL;
                			free(tmp);
                			return 1;
           			 }

				else if(leftvalid==1)
				{
					tmp->parent->child=NULL;
                			free(tmp);
              				return 1;
				}
			}

			else if (rightvalid==2)
			{
				leftvalid=leftSiblingCheck(tmp);

				if(leftvalid==2)
				{
					tmp->leftsibling->rightsibling=tmp->rightsibling;
                			tmp->rightsibling->leftsibling=tmp->leftsibling;
                			free(tmp);
                			return 1;
				}	
            
            			else if(leftvalid==1)
            			{	
                			tmp->rightsibling->leftsibling=NULL;
                			tmp->parent->child=tmp->rightsibling;
                			free(tmp);
                			return 1;
            			}
            
        		}
    	}
	}

    }
}

